# This module is loosely based on MT::ConfigMgr found in MT 3.1
package MT::ConfigMgr::Plugin;
use strict;

use vars qw( $VERSION );
$VERSION = 0.32;

# should have a default key if saved blanked or force key to be set?
# what about checking multiple configs with the same plugin/key exist?

use base qw( MT::ErrorHandler );

use MT::Request;
use MT::PluginData;

sub new {
    my $mgr = bless {__var => {}}, $_[0];
    $mgr->init;
    $mgr;
}

sub init { die 'The init method must be overridden.' }

sub define {
    my $mgr = shift;
    my ($var, %param) = @_;
    $mgr->{__var}{$var} = undef;
    $mgr->{__settings}{$var} = keys %param ? \%param : {};
    if (exists $param{Default}) {
        $mgr->set($var, $param{Default});
    }
}

sub get { $_[0]->{__var}{$_[1]} }

sub set {
    my $mgr = shift;
    my ($var, $val) = @_;
    if (my $type = $mgr->{__settings}{$var}{Type}) {
        if ($type eq 'ARRAY') {
            push @{$mgr->{__var}{$var}}, $val;
        } elsif ($type eq 'HASH') {
            (my ($key), $val) = split /=/, $val;
            $mgr->{__var}{$var}{$key} = $val;
        }
    } else {
        $mgr->{__var}{$var} = $val;
    }
}

sub read_config {
    my $class = shift;
    my $key   = shift;
    my $args  = {plugin => $class};
    $args->{key} = $key if defined $key;
    my @cfg;
    my @obj = MT::PluginData->load($args);
    if (defined $key && !@obj) {
        my $mgr = $class->new;
        $mgr->{__key} = $key;
        push(@cfg, $mgr);
    } else {
        foreach my $pdo (@obj) {
            my $mgr = $class->new;
            $mgr->{__id}  = $pdo->id;
            $mgr->{__key} = $pdo->key;
            my $data = $pdo->data;
            map { $mgr->set($_, $data->{$_}) } keys %$data if $data;
            push(@cfg, $mgr);
        }
    }
    MT::Request->instance->stash("${class}::cfg",
                                 $cfg[0])    # backwards compatability
      if (@cfg == 1 && $cfg[0]->key && $cfg[0]->key eq '#CONFIG');
    wantarray ? @cfg : $cfg[0];
}

sub save_config {
    my $mgr  = shift;
    my $data = {};
    map { $data->{$_} = $mgr->{__var}->{$_} }
      grep {
        !exists $mgr->{__settings}->{$_}->{Default}
          || $mgr->{__var}->{$_} ne $mgr->{__settings}->{$_}->{Default}
      }
      keys %{$mgr->{__settings}};
    my $pdo;
    unless ($mgr->{__id}) {
        $pdo = MT::PluginData->new;
        $pdo->plugin(ref($mgr));
    } else {
        $pdo = MT::PluginData->load($mgr->{__id});
    }
    $pdo->key($mgr->{__key});    # key could have changed.
    $pdo->data($data);
    $pdo->save or return $mgr->error($pdo->errstr);
    $mgr->{__id} = $pdo->id;     # make sure newly saved cfg has its PDO ID.
    1;
}

sub reset_config {
    my $mgr = shift;
    return $mgr->error('The configuration cannot be reset. It wasn\'t saved.')
      unless $mgr->id;
    my $pdo = MT::PluginData->load($mgr->id)
      || return $mgr->error(MT::PluginData->errstr);
    if ($pdo) {
        $pdo->remove || return $mgr->error($pdo->errstr);
        $mgr->{__id}  = undef;
        $mgr->{__var} = undef;
        $mgr->init;
    }
    1;
}

sub id          { $_[0]->{__id} }
sub data        { $_[0]->{__var} }
sub config_keys { keys %{$_[0]->{__settings}} }

sub key {
    $_[0]->{__key} = $_[1] if defined $_[1];
    $_[0]->{__key};
}

# Change from AUTOLOAD to a mk_accessor-like process instead.

sub DESTROY { }

use vars qw( $AUTOLOAD );

sub AUTOLOAD {
    my $mgr = $_[0];
    (my $var = $AUTOLOAD) =~ s!.+::!!;
    die MT->translate("No such config variable '[_1]'", $var)
      unless exists $mgr->{__var}->{$var};
    no strict 'refs';
    *$AUTOLOAD = sub {
        my $mgr = shift;
        @_ ? $mgr->set($var, $_[0]) : $mgr->get($var);
    };
    goto &$AUTOLOAD;
}

#--- deprecated

sub instance {
    my $class = shift;
    my $r     = MT::Request->instance;
    return $r->stash("${class}::cfg") if $r->stash("${class}::cfg");
    $r->stash("${class}::cfg", $class->new);
    $r->stash("${class}::cfg");
}

1;

__END__

=head1 NAME

MT::ConfigMgr::Plugin - a base class for creating
object-oriented configuration objects.

=head1 VERSION

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=head1 AUTHOR & COPYRIGHT

MT::ConfigMgr::Plugin is Copyright 2004-2006, Timothy
Appnel, Appnel Internet Solutions, LLC. http://appnel.com/

This program is free software; you can use, modify, and
redistribute it under the same terms as Perl 5.8.x itself.

See http://www.perl.com/perl/misc/Artistic.html

=cut

